/*
*********************************************************************************************************
*                                            EXAMPLE CODE
*
*               This file is provided as an example on how to use Micrium products.
*
*               Please feel free to use any application code labeled as 'EXAMPLE CODE' in
*               your application products.  Example code may be used as is, in whole or in
*               part, or may be used as a reference only. This file can be modified as
*               required to meet the end-product requirements.
*
*********************************************************************************************************
*/

/*
*********************************************************************************************************
*
*                                   HTTP INSTANCE SERVER HOOKS FILE
*
* Filename : app_no_fs_http-s_hooks.c
* Version  : V3.01.00
*********************************************************************************************************
*/

/*
*********************************************************************************************************
*********************************************************************************************************
*                                             INCLUDE FILES
*********************************************************************************************************
*********************************************************************************************************
*/

#include  "app_no_fs.h"
#include  "app_no_fs_http-s_instance_cfg.h"


/*
*********************************************************************************************************
*********************************************************************************************************
*                                               DEFINES
*********************************************************************************************************
*********************************************************************************************************
*/

#define  DFLT_PAGE_URL             "/hello_world"
#define  DFLT_PAGE_DATA            "hello world!"


/*
*********************************************************************************************************
*********************************************************************************************************
*                                        FUNCTIONS PROTOTYPES
*********************************************************************************************************
*********************************************************************************************************
*/

static  CPU_BOOLEAN  HTTPs_ReqHook               (const  HTTPs_INSTANCE         *p_instance,
                                                         HTTPs_CONN             *p_conn,
                                                  const  void                   *p_hook_cfg);


static  CPU_BOOLEAN  HTTPs_RespHdrTxHook         (const  HTTPs_INSTANCE         *p_instance,
                                                         HTTPs_CONN             *p_conn,
                                                  const  void                   *p_hook_cfg);


/*
*********************************************************************************************************
*                                      HTTP SERVER HOOK CONFIGURATION
*
* Note(s): (1)  When the instance is created, an hook function can be called to initialize connection objects used by the instance.
*               If the hook is not required by the upper application, it can be set as DEF_NULL and no function will be called.
*               See HTTPs_InstanceInitHook() function for further details.
*
*          (2)  Each time a header field other than the default one is received, a hook function is called
*               allowing to choose which header field(s) to keep for further processing.
*               If the hook is not required by the upper application, it can be set as DEF_NULL and no function will be called.
*               See HTTPs_ReqHdrRxHook() function for further details.
*
*          (3)  For each new incoming connection request a hook function can be called by the web server to authenticate
*               the remote connection to accept or reject it. This function can have access to allow stored request header
*               field.
*               If the hook is not required by the upper application, it can be set as DEF_NULL and no function will be called.
*               See HTTPs_ReqHook() function for further details.
*
*          (4)  If the upper application want to parse the data received in the request body itself, a hook function is available.
*               It will be called each time new data are received. The exception is when a POST request with a form is
*               received. In that case, the HTTP server core will parse the body and saved the data into Key-Value blocks.
*               If the hook is not required by the upper application, it can be set as DEF_NULL and no function will be called.
*               See HTTPs_ReqBodyRxHook() function for further details.
*
*          (5)  The Signal hook function occurs after the HTTP request has been completely received.
*               The hook function SHOULD NOT be blocking and SHOULD return quickly. A time consuming function will
*               block the processing of the other connections and reduce the HTTP server performance.
*               In case the request processing is time consuming, the Poll hook function SHOULD be enabled to
*               allow the server to periodically verify if the upper application has finished the request processing.
*               If the hook is not required by the upper application, it can be set as DEF_NULL and no function will be called.
*               See HTTPs_ReqRdySignalHook() function for further details.
*
*          (6)  The Poll hook function SHOULD be enable in case the request processing require lots of time. It
*               allows the HTTP server to periodically poll the upper application and verify if the request processing
*               has finished.
*               If the Poll feature is not required, this field SHOULD be set as DEF_NULL.
*               See HTTPs_ReqRdyPollHook() function for further details.
*
*          (7)  Before an HTTP response message is transmitted, a hook function is called to enable adding header field(s) to
*               the message before it is sent.
*               The Header Module must be enabled for this hook to be called. See HTTPs_CFG_HDR in http-s_cfg.h.
*               If the hook is not required by the upper application, it can be set as DEF_NULL and no function will be called.
*               See HTTPs_RespHdrTxHook() function for further details.
*
*          (8)  The hook function is called by the web server when a token is found. This means the hook
*               function must fill a buffer with the value of the instance token to be sent.
*               If the feature is not enabled, this field is not used and can be set as DEF_NULL.
*               See 'HTTPs_RespTokenValGetHook' for further information.
*
*          (9)  To allow the upper application to transmit data with the Chunked Transfer Encoding, a hook function is
*               available. If defined, it will be called at the moment of the Response body transfer, and it will be called
*               until the application has transfer all its data.
*               If the hook is not required by the upper application, it can be set as DEF_NULL and no function will be called.
*               See HTTPs_RespChunkDataGetHook() function for further details.
*
*          (10) Once an HTTP transaction is completed, a hook function can be called to notify the upper application that the
*               transaction is done. This hook function could be used to free some previously allocated memory.
*               If the hook is not required by the upper application, it can be set as DEF_NULL and no function will be called.
*               See HTTPs_TransCompleteHook() function for further details.
*
*          (11) When an internal error occurs during the processing of a connection a hook function can be called to
*               notify the application of the error and to change the behavior such as the status code and the page returned.
*               If the hook is not required by the upper application, it can be set as DEF_NULL and no function will be called.
*               See HTTPs_ErrHook() function for further details.
*
*          (12) Get error file hook can be called every time an error has occurred when processing a connection.
*               This function can set the web page that should be transmit instead of the default error page defined
*               in http-s_cfg.h.
*               If set to DEF_NULL the default error page will be used for every error.
*               See HTTPs_ErrFileGetHook() function for further details.
*
*          (13) Once a connection is closed a hook function can be called to notify the upper application that a connection
*               is no more active. This hook function could be used to free some previously allocated memory.
*               If the hook is not required by the upper application, it can be set as DEF_NULL and no function will be called.
*               See HTTPs_ConnCloseHook() function for further details.
*********************************************************************************************************
*/

const  HTTPs_HOOK_CFG  HTTPs_Hooks_NoFS = {
        DEF_NULL,                                   /* .OnInstanceInitHook     See Note #1.     */
        DEF_NULL,                                   /* .OnReqHdrRxHook         See Note #2.     */
        HTTPs_ReqHook,                              /* .OnReqHook              See Note #3.     */
        DEF_NULL,                                   /* .OnReqBodyRxHook        See Note #4.     */
        DEF_NULL,                                   /* .OnReqRdySignalHook     See Note #5.     */
        DEF_NULL,                                   /* .OnReqRdyPollHook       See Note #6.     */
        HTTPs_RespHdrTxHook,                        /* .OnRespHdrTxHook        See Note #7.     */
        DEF_NULL,                                   /* .OnRespTokenHook        See Note #8.     */
        DEF_NULL,                                   /* .OnRespChunkHook        See Note #9.     */
        DEF_NULL,                                   /* .OnTransCompleteHook    See Note #10.    */
        DEF_NULL,                                   /* .OnErrHook              See Note #11.    */
        DEF_NULL,                                   /* .OnErrFileGetHook       See Note #12.    */
        DEF_NULL                                    /* .OnConnCloseHook        See Note #13.    */
};


/*
*********************************************************************************************************
*                                          HTTPs_ReqHook()
*
* Description : Called after the parsing of an HTTP request message's first line and header(s).
*               Allows the application to process the information received in the request message.
*               Examples of behaviors that could be implemented :
*
*               (a) Analyze the Request-URI and validate that the client has the permission to access
*                   the resource. If not, change the Response Status Code to 403 (Forbidden) or 401
*                   (Unauthorized) if an Authentication technique is implemented. In case of a 401
*                   Status, a "WWW-Authenticate" header needs to be added to the response message
*                   (See HTTPs_InstanceRespHdrTx() function)
*
*               (b) Depending on whether the header feature is enabled and which header fields have been
*                   chosen for use (see HTTPs_ReqHdrRxHook() function), different behaviors
*                   are possible. Here are some examples :
*
*                       (1) A "Cookie" header is received. The default html page is modified to include
*                           personalized features for the client.
*
*                       (2) An "Authorization" header is received. This validates that the client login is good and
*                           changes permanently its' access to the folder/file.
*
*                       (3) An "If-Modified-Since" header is received. It then validates whether or not the resource
*                           has been modified since the 'HTTP-date' received with the header. If it was, continue
*                           with the request processing normally, else change the Status Code to 304 (Not Modified).
*
*
* Argument(s) : p_instance  Pointer to the HTTPs instance object.
*
*               p_conn      Pointer to the HTTPs connection object.
*
*               p_hook_cfg  Pointer to hook configuration object.
*
* Return(s)   : DEF_OK    if the application allows the request to be continue.
*               DEF_FAIL  otherwise.
*                               Status code will be set automatically to HTTPs_STATUS_UNAUTHORIZED
*
* Caller(s)   : HTTPs_Req() via 'p_cfg->HooksPtr->OnReqHook'.
*
* Note(s)     : (1) The instance structure is for read-only. It must not be modified at any point in this hook function.
*
*               (2) The following connection attributes can be accessed to analyze the connection:
*
*                   (a) 'ClientAddr'
*                           This connection parameter contains the IP address and port used by the remote client to access the
*                           server instance.
*
*                   (b) 'Method'
*                           HTTPs_METHOD_GET        Get  request
*                           HTTPs_METHOD_POST       Post request
*                           HTTPs_METHOD_HEAD       Head request
*
*                   (c) 'PathPtr'
*                           This is a pointer to the string that contains the name of the file requested.
*
*                   (d) 'HdrCtr'
*                           This parameter is a counter of the number of header field that has been stored.
*
*                   (e) 'HdrListPtr'
*                           This parameter is a pointer to the first header field stored. A linked list is created with
*                           all header field stored.
*
*               (3) In this hook function, only the under-mentioned connection parameters are allowed
*                   to be modified :
*
*                   (a) 'StatusCode'
*
*                           See HTTPs_STATUS_CODE declaration in http-s.h for all the status code supported.
*
*                   (b) 'PathPtr'
*
*                           This is a pointer to the string that contains the name of the file requested. You can change
*                           the name of the requested file to send another file instead without error.
*
*                   (c) 'DataPtr'
*
*                           This is a pointer to the data file or data to transmit. This parameter should be null when calling
*                           this function. If data from memory has to be sent instead of a file, this pointer must be set
*                           to the location of the data.
*
*                   (d) 'RespBodyDataType'
*
*                           HTTPs_BODY_DATA_TYPE_FILE              Open and transmit a file. Value by default.
*                           HTTPs_BODY_DATA_TYPE_STATIC_DATA       Transmit data from the memory. Must be set by the hook function.
*                           HTTPs_BODY_DATA_TYPE_NONE              No body in response.
*
*                   (e) 'DataLen'
*
*                           0,                              Default value, will be set when the file is opened.
*                           Data length,                    Must be set by the data length when transmitting data from
*                                                           the memory
*
*                   (f) 'ConnDataPtr'
*
*                           This is a pointer available for the upper application when memory block must be allocated
*                           to process the connection request. If memory is allocated by the upper application, the memory
*                           space can be deallocated into another hook function.
*
*               (4) When the Location of the requested file has changed, besides the Status Code to change (3xx),
*                   the 'PathPtr' parameter needs to be updated. A "Location" header will be added automatically in
*                   the response by uC/HTTPs core with the new location.
*********************************************************************************************************
*/

static  CPU_BOOLEAN  HTTPs_ReqHook (const  HTTPs_INSTANCE  *p_instance,
                                           HTTPs_CONN      *p_conn,
                                    const  void            *p_hook_cfg)
{
    CPU_INT16S  str_cmp;
    HTTPs_ERR   err;

                                                                /* Set the HTTP response body.                          */
    str_cmp = Str_Cmp_N(p_conn->PathPtr, DFLT_PAGE_URL, p_conn->PathLenMax);
    if (str_cmp == 0) {

        HTTPs_RespBodySetParamStaticData(p_instance,
                                         p_conn,
                                         HTTP_CONTENT_TYPE_HTML,
                                         DFLT_PAGE_DATA,
                                         sizeof(DFLT_PAGE_DATA),
                                         DEF_NO,
                                        &err);
        if (err != HTTPs_ERR_NONE) {
            return (DEF_FAIL);
        }
    }

    return (DEF_OK);
}


/*
*********************************************************************************************************
*                                        HTTPs_RespHdrTxHook()
*
* Description : Called each time the HTTP server is building a response message. Allows for adding header
*               fields to the response message according to the application needs.
*
* Argument(s) : p_instance  Pointer to the HTTPs instance object.
*
*               p_conn      Pointer to the HTTPs connection object.
*
*               p_hook_cfg  Pointer to hook configuration object.
*
* Return(s)   : DEF_YES,    if the header fields are added without running into a error.
*
*               DEF_NO,     otherwise.
*
* Caller(s)   : HTTPsResp_Hdr() via 'p_cfg->OnRespHdrTxHook()'.
*
* Note(s)     : (1) The instance structure MUST NOT be modified.
*
*               (2) The connection structure MUST NOT be modified manually since the response is about to be
*                   transmitted at this point. The only change to the connection structure should be the
*                   addition of header fields for the response message through the function HTTPs_RespHdrGet().
*********************************************************************************************************
*/

static  CPU_BOOLEAN  HTTPs_RespHdrTxHook (const  HTTPs_INSTANCE  *p_instance,
                                                 HTTPs_CONN      *p_conn,
                                          const  void            *p_hook_cfg)
{
#if (HTTPs_CFG_HDR_TX_EN == DEF_ENABLED)

           HTTP_HDR_BLK  *p_resp_hdr_blk;
    const  HTTPs_CFG     *p_cfg;
           CPU_CHAR      *str_data;
           CPU_SIZE_T     str_len;
           HTTPs_ERR      http_err;


    p_cfg = p_instance->CfgPtr;

    if (p_cfg->HdrTxCfgPtr == DEF_NULL) {
        return (DEF_NO);
    }

    switch (p_conn->StatusCode) {
           case HTTP_STATUS_OK:

                if (p_conn->ReqContentType == HTTP_CONTENT_TYPE_HTML) {

                                                                /* --------------- ADD SERVER HDR FIELD --------------- */
                                                                /* Get and add header block to the connection.          */
                    p_resp_hdr_blk = HTTPs_RespHdrGet(p_instance,
                                                      p_conn,
                                                      HTTP_HDR_FIELD_SERVER,
                                                      HTTP_HDR_VAL_TYPE_STR_DYN,
                                                     &http_err);
                    if (p_resp_hdr_blk == DEF_NULL) {
                        return(DEF_FAIL);
                    }

                    str_data = "uC-HTTP-server";                /* Build Server string value.                           */

                    str_len = Str_Len_N(str_data, p_cfg->HdrTxCfgPtr->DataLenMax);

                                                                /* update hdr blk parameter.                            */
                    Str_Copy_N(p_resp_hdr_blk->ValPtr,
                               str_data,
                               str_len);

                    p_resp_hdr_blk->ValLen = str_len;
                }
                break;


           default:
                break;
    }
#endif

    return (DEF_YES);
}
